import Formatter from '../core/Formatter';
import Tokenizer from '../core/Tokenizer';

const reservedWords = [
  'ABORT',
  'ABSOLUTE',
  'ACCESS',
  'ACTION',
  'ADD',
  'ADMIN',
  'AFTER',
  'AGGREGATE',
  'ALL',
  'ALSO',
  'ALTER',
  'ALWAYS',
  'ANALYSE',
  'ANALYZE',
  'AND',
  'ANY',
  'ARRAY',
  'AS',
  'ASC',
  'ASSERTION',
  'ASSIGNMENT',
  'ASYMMETRIC',
  'AT',
  'ATTACH',
  'ATTRIBUTE',
  'AUTHORIZATION',
  'BACKWARD',
  'BEFORE',
  'BEGIN',
  'BETWEEN',
  'BIGINT',
  'BINARY',
  'BIT',
  'BOOLEAN',
  'BOTH',
  'BY',
  'CACHE',
  'CALL',
  'CALLED',
  'CASCADE',
  'CASCADED',
  'CASE',
  'CAST',
  'CATALOG',
  'CHAIN',
  'CHAR',
  'CHARACTER',
  'CHARACTERISTICS',
  'CHECK',
  'CHECKPOINT',
  'CLASS',
  'CLOSE',
  'CLUSTER',
  'COALESCE',
  'COLLATE',
  'COLLATION',
  'COLUMN',
  'COLUMNS',
  'COMMENT',
  'COMMENTS',
  'COMMIT',
  'COMMITTED',
  'CONCURRENTLY',
  'CONFIGURATION',
  'CONFLICT',
  'CONNECTION',
  'CONSTRAINT',
  'CONSTRAINTS',
  'CONTENT',
  'CONTINUE',
  'CONVERSION',
  'COPY',
  'COST',
  'CREATE',
  'CROSS',
  'CSV',
  'CUBE',
  'CURRENT',
  'CURRENT_CATALOG',
  'CURRENT_DATE',
  'CURRENT_ROLE',
  'CURRENT_SCHEMA',
  'CURRENT_TIME',
  'CURRENT_TIMESTAMP',
  'CURRENT_USER',
  'CURSOR',
  'CYCLE',
  'DATA',
  'DATABASE',
  'DAY',
  'DEALLOCATE',
  'DEC',
  'DECIMAL',
  'DECLARE',
  'DEFAULT',
  'DEFAULTS',
  'DEFERRABLE',
  'DEFERRED',
  'DEFINER',
  'DELETE',
  'DELIMITER',
  'DELIMITERS',
  'DEPENDS',
  'DESC',
  'DETACH',
  'DICTIONARY',
  'DISABLE',
  'DISCARD',
  'DISTINCT',
  'DO',
  'DOCUMENT',
  'DOMAIN',
  'DOUBLE',
  'DROP',
  'EACH',
  'ELSE',
  'ENABLE',
  'ENCODING',
  'ENCRYPTED',
  'END',
  'ENUM',
  'ESCAPE',
  'EVENT',
  'EXCEPT',
  'EXCLUDE',
  'EXCLUDING',
  'EXCLUSIVE',
  'EXECUTE',
  'EXISTS',
  'EXPLAIN',
  'EXPRESSION',
  'EXTENSION',
  'EXTERNAL',
  'EXTRACT',
  'FALSE',
  'FAMILY',
  'FETCH',
  'FILTER',
  'FIRST',
  'FLOAT',
  'FOLLOWING',
  'FOR',
  'FORCE',
  'FOREIGN',
  'FORWARD',
  'FREEZE',
  'FROM',
  'FULL',
  'FUNCTION',
  'FUNCTIONS',
  'GENERATED',
  'GLOBAL',
  'GRANT',
  'GRANTED',
  'GREATEST',
  'GROUP',
  'GROUPING',
  'GROUPS',
  'HANDLER',
  'HAVING',
  'HEADER',
  'HOLD',
  'HOUR',
  'IDENTITY',
  'IF',
  'ILIKE',
  'IMMEDIATE',
  'IMMUTABLE',
  'IMPLICIT',
  'IMPORT',
  'IN',
  'INCLUDE',
  'INCLUDING',
  'INCREMENT',
  'INDEX',
  'INDEXES',
  'INHERIT',
  'INHERITS',
  'INITIALLY',
  'INLINE',
  'INNER',
  'INOUT',
  'INPUT',
  'INSENSITIVE',
  'INSERT',
  'INSTEAD',
  'INT',
  'INTEGER',
  'INTERSECT',
  'INTERVAL',
  'INTO',
  'INVOKER',
  'IS',
  'ISNULL',
  'ISOLATION',
  'JOIN',
  'KEY',
  'LABEL',
  'LANGUAGE',
  'LARGE',
  'LAST',
  'LATERAL',
  'LEADING',
  'LEAKPROOF',
  'LEAST',
  'LEFT',
  'LEVEL',
  'LIKE',
  'LIMIT',
  'LISTEN',
  'LOAD',
  'LOCAL',
  'LOCALTIME',
  'LOCALTIMESTAMP',
  'LOCATION',
  'LOCK',
  'LOCKED',
  'LOGGED',
  'MAPPING',
  'MATCH',
  'MATERIALIZED',
  'MAXVALUE',
  'METHOD',
  'MINUTE',
  'MINVALUE',
  'MODE',
  'MONTH',
  'MOVE',
  'NAME',
  'NAMES',
  'NATIONAL',
  'NATURAL',
  'NCHAR',
  'NEW',
  'NEXT',
  'NFC',
  'NFD',
  'NFKC',
  'NFKD',
  'NO',
  'NONE',
  'NORMALIZE',
  'NORMALIZED',
  'NOT',
  'NOTHING',
  'NOTIFY',
  'NOTNULL',
  'NOWAIT',
  'NULL',
  'NULLIF',
  'NULLS',
  'NUMERIC',
  'OBJECT',
  'OF',
  'OFF',
  'OFFSET',
  'OIDS',
  'OLD',
  'ON',
  'ONLY',
  'OPERATOR',
  'OPTION',
  'OPTIONS',
  'OR',
  'ORDER',
  'ORDINALITY',
  'OTHERS',
  'OUT',
  'OUTER',
  'OVER',
  'OVERLAPS',
  'OVERLAY',
  'OVERRIDING',
  'OWNED',
  'OWNER',
  'PARALLEL',
  'PARSER',
  'PARTIAL',
  'PARTITION',
  'PASSING',
  'PASSWORD',
  'PLACING',
  'PLANS',
  'POLICY',
  'POSITION',
  'PRECEDING',
  'PRECISION',
  'PREPARE',
  'PREPARED',
  'PRESERVE',
  'PRIMARY',
  'PRIOR',
  'PRIVILEGES',
  'PROCEDURAL',
  'PROCEDURE',
  'PROCEDURES',
  'PROGRAM',
  'PUBLICATION',
  'QUOTE',
  'RANGE',
  'READ',
  'REAL',
  'REASSIGN',
  'RECHECK',
  'RECURSIVE',
  'REF',
  'REFERENCES',
  'REFERENCING',
  'REFRESH',
  'REINDEX',
  'RELATIVE',
  'RELEASE',
  'RENAME',
  'REPEATABLE',
  'REPLACE',
  'REPLICA',
  'RESET',
  'RESTART',
  'RESTRICT',
  'RETURNING',
  'RETURNS',
  'REVOKE',
  'RIGHT',
  'ROLE',
  'ROLLBACK',
  'ROLLUP',
  'ROUTINE',
  'ROUTINES',
  'ROW',
  'ROWS',
  'RULE',
  'SAVEPOINT',
  'SCHEMA',
  'SCHEMAS',
  'SCROLL',
  'SEARCH',
  'SECOND',
  'SECURITY',
  'SELECT',
  'SEQUENCE',
  'SEQUENCES',
  'SERIALIZABLE',
  'SERVER',
  'SESSION',
  'SESSION_USER',
  'SET',
  'SETOF',
  'SETS',
  'SHARE',
  'SHOW',
  'SIMILAR',
  'SIMPLE',
  'SKIP',
  'SMALLINT',
  'SNAPSHOT',
  'SOME',
  'SQL',
  'STABLE',
  'STANDALONE',
  'START',
  'STATEMENT',
  'STATISTICS',
  'STDIN',
  'STDOUT',
  'STORAGE',
  'STORED',
  'STRICT',
  'STRIP',
  'SUBSCRIPTION',
  'SUBSTRING',
  'SUPPORT',
  'SYMMETRIC',
  'SYSID',
  'SYSTEM',
  'TABLE',
  'TABLES',
  'TABLESAMPLE',
  'TABLESPACE',
  'TEMP',
  'TEMPLATE',
  'TEMPORARY',
  'TEXT',
  'THEN',
  'TIES',
  'TIME',
  'TIMESTAMP',
  'TO',
  'TRAILING',
  'TRANSACTION',
  'TRANSFORM',
  'TREAT',
  'TRIGGER',
  'TRIM',
  'TRUE',
  'TRUNCATE',
  'TRUSTED',
  'TYPE',
  'TYPES',
  'UESCAPE',
  'UNBOUNDED',
  'UNCOMMITTED',
  'UNENCRYPTED',
  'UNION',
  'UNIQUE',
  'UNKNOWN',
  'UNLISTEN',
  'UNLOGGED',
  'UNTIL',
  'UPDATE',
  'USER',
  'USING',
  'VACUUM',
  'VALID',
  'VALIDATE',
  'VALIDATOR',
  'VALUE',
  'VALUES',
  'VARCHAR',
  'VARIADIC',
  'VARYING',
  'VERBOSE',
  'VERSION',
  'VIEW',
  'VIEWS',
  'VOLATILE',
  'WHEN',
  'WHERE',
  'WHITESPACE',
  'WINDOW',
  'WITH',
  'WITHIN',
  'WITHOUT',
  'WORK',
  'WRAPPER',
  'WRITE',
  'XML',
  'XMLATTRIBUTES',
  'XMLCONCAT',
  'XMLELEMENT',
  'XMLEXISTS',
  'XMLFOREST',
  'XMLNAMESPACES',
  'XMLPARSE',
  'XMLPI',
  'XMLROOT',
  'XMLSERIALIZE',
  'XMLTABLE',
  'YEAR',
  'YES',
  'ZONE',
];

const reservedTopLevelWords = [
  'ADD',
  'AFTER',
  'ALTER COLUMN',
  'ALTER TABLE',
  'CASE',
  'DELETE FROM',
  'END',
  'EXCEPT',
  'FETCH FIRST',
  'FROM',
  'GROUP BY',
  'HAVING',
  'INSERT INTO',
  'INSERT',
  'LIMIT',
  'ORDER BY',
  'SELECT',
  'SET CURRENT SCHEMA',
  'SET SCHEMA',
  'SET',
  'UPDATE',
  'VALUES',
  'WHERE',
];

const reservedTopLevelWordsNoIndent = ['INTERSECT', 'INTERSECT ALL', 'UNION', 'UNION ALL'];

const reservedNewlineWords = [
  'AND',
  'ELSE',
  'OR',
  'WHEN',
  // joins
  'JOIN',
  'INNER JOIN',
  'LEFT JOIN',
  'LEFT OUTER JOIN',
  'RIGHT JOIN',
  'RIGHT OUTER JOIN',
  'FULL JOIN',
  'FULL OUTER JOIN',
  'CROSS JOIN',
  'NATURAL JOIN',
];

export default class PostgreSqlFormatter extends Formatter {
  tokenizer() {
    return new Tokenizer({
      reservedWords,
      reservedTopLevelWords,
      reservedNewlineWords,
      reservedTopLevelWordsNoIndent,
      stringTypes: [`""`, "''", "U&''", 'U&""', '$$'],
      openParens: ['(', 'CASE'],
      closeParens: [')', 'END'],
      indexedPlaceholderTypes: ['$'],
      namedPlaceholderTypes: [':'],
      lineCommentTypes: ['--'],
      operators: [
        '!=',
        '<<',
        '>>',
        '||/',
        '|/',
        '::',
        '->>',
        '->',
        '~~*',
        '~~',
        '!~~*',
        '!~~',
        '~*',
        '!~*',
        '!~',
        '!!',
      ],
    });
  }
}
